import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import {
  Response,
  ResponseParam,
  UserError,
  CurrentError,
} from '../../common/enums/response';
import { ApiErrorCode } from '../../common/enums/api-error-code.enum';
import { Device } from 'src/entities/device.entity';
import { PgaeDto } from './device.dto';
import { AdminRole, User, UserRole } from 'src/entities/user.entity';
import { Sys } from 'src/entities/sys.entity';
import { Caller } from 'src/entities/caller.entity';
import { Log } from 'src/entities/log.entity';
import { getMinutesDiff } from 'src/common/utils';
import { SmsConfig, SmsSender } from 'src/common/smsSender';
import { VoiceCaller } from 'src/common/voiceCaller';

@Injectable()
export class DeviceService {
  constructor() {}
  @InjectRepository(Device) private readonly device: Repository<Device>;
  @InjectRepository(User) private readonly user: Repository<User>;
  @InjectRepository(Sys) private readonly sys: Repository<Sys>;
  @InjectRepository(Caller) private readonly caller: Repository<Caller>;
  @InjectRepository(Log) private readonly log: Repository<Log>;

  /**
   * @description: 创建设备
   * @param {any} param
   * @return {*}
   */
  public async created(param: any): Promise<object> {
    try {
      const date = new Date();
      date.setFullYear(new Date().getFullYear() + 1);
      param.expireTime = date;
      param.p_created_at = new Date();
      param.p_updated_at = new Date();
      await this.device.save(param);
      let responseParam: ResponseParam = {
        message: ApiErrorCode.LACK_SET_SUCCESS,
        data: null,
      };
      return Response(responseParam);
    } catch (error) {
      console.log(error);
      return CurrentError.LACK_SET_FAIL;
    }
  }

  /**
   * @description: 修改设备
   * @param {any} param
   * @return {*}
   */
  public async put(id: number, param: any): Promise<object> {
    try {
      delete param.id;
      param.p_updated_at = new Date();
      await this.device.update({ id }, param);
      let responseParam: ResponseParam = {
        message: ApiErrorCode.LACK_UPDATE_SUCCESS,
        data: null,
      };
      return Response(responseParam);
    } catch (error) {
      return CurrentError.LACK_UPDATE_FAIL;
    }
  }

  /**
   *
   * @description 删除设备
   * @param {number} id
   */
  public async delete(id: number): Promise<object> {
    try {
      await this.device.update({ id }, { p_deleted_at: new Date() });
      let responseParam: ResponseParam = {
        message: ApiErrorCode.LACK_DEL_SUCCESS,
        data: null,
      };
      return Response(responseParam);
    } catch (error) {
      return CurrentError.LACK_DEL_FAIL;
    }
  }

  /**
   *
   * @description 查询设备列表
   * @param {number} page
   * @param {number} pageSize
   * @param {string} name
   */
  public async getList(param: PgaeDto) {
    let listRep: any = this.device
      .createQueryBuilder()
      .where('p_deleted_at is null');
    if (param.name) {
      listRep.andWhere('name like :name', { name: `%${param.name}%` });
    }
    if (param.identifier) {
      listRep.andWhere('identifier like :identifier', {
        identifier: `%${param.identifier}%`,
      });
    }
    if (param.status) {
      listRep.andWhere('status = :status', { status: param.status });
    }
    if (param.userName) {
      listRep.andWhere('userName like :userName', {
        userName: `%${param.userName}%`,
      });
    }
    if (param.type) {
      listRep.andWhere('type = :type', { type: param.type });
    }
    const list: any = await listRep
      .orderBy('p_created_at', 'DESC')
      .skip((param.page - 1) * param.pageSize)
      .take(param.pageSize)
      .getManyAndCount();
    let responseParam: ResponseParam = {
      message: ApiErrorCode.LACK_GET_SUCCESS,
      data: list[0],
      count: list[1],
    };
    return Response(responseParam);
  }

  /**
   *
   * @description 获取用户设备
   */
  public async getUserList(userId: number, type: string, status?: string) {
    let listRep = this.device
      .createQueryBuilder()
      .where('userId = :userId', { userId })
      .andWhere('type = :type', { type })
      .andWhere('p_deleted_at is null');

    if (status) {
      listRep.andWhere('status = :status', { status: status });
    }

    const data = await listRep.getMany();
    let responseParam: ResponseParam = {
      message: ApiErrorCode.LACK_GET_SUCCESS,
      data: data,
    };
    return Response(responseParam);
  }

  /**
   *
   * @description 查询设备详情
   * @param {number} id
   */
  public async getInfo(id: number) {
    try {
      const data: Device = await this.device.findOneBy({ id });
      let responseParam: ResponseParam = {
        message: ApiErrorCode.LACK_GET_SUCCESS,
        data,
      };
      return Response(responseParam);
    } catch (error) {
      return CurrentError.LACK_GET_FAIL;
    }
  }

  /**
   *
   * @description 查询设备数量
   */
  public async getNumber(userId: number) {
    try {
      const data: Device = await this.device.query(
        "SELECT SUM(type = 'power') as power,SUM(type = 'gateway') as gateway,SUM(type = 'button') as button,SUM(type = 'environment') as environment,SUM(type = 'other') as other,SUM(status = 'offline') as offline,SUM(status = 'online') as online FROM device WHERE userId = " +
          userId,
      );
      let responseParam: ResponseParam = {
        message: ApiErrorCode.LACK_GET_SUCCESS,
        data,
      };
      return Response(responseParam);
    } catch (error) {
      return CurrentError.LACK_GET_FAIL;
    }
  }

  async phoneTasks(list: Caller[], warnList: string[]) {
    let _warnList = JSON.parse(JSON.stringify(warnList));
    let task = setInterval(
      () => {
        if (!_warnList[0]) {
          clearInterval(task);
        } else {
          // 执行业务
          const warn = _warnList[0];
          for (let i = 0; i < list.length; i++) {
            const el = list[i];
            const config: SmsConfig = {
              accessKeyId: 'LTAI5tEidvcjyvfvLvSUBT3i',
              accessKeySecret: 'CDg4BZiqnQPEqbUCZHlwzoOexjSeiX',
            };
            const phoneSender = new VoiceCaller(config);
            const data = {
              CalledNumber: el.phone,
              SignName: '五号风控',
              TtsCode: 'TTS_316545191',
              TtsParam: JSON.stringify({
                name: el.name,
                content: warn,
              }),
              playTimes: 2,
            };
            phoneSender.sendVoiceCall(data);
          }
          _warnList.splice(0, 1);
        }
      },
      1 * 60 * 1000,
    );
  }

  async smsTasks(list: Caller[], warnList: string[], IMEI: string) {
    // console.log()
    let _warnList = JSON.parse(JSON.stringify(warnList));
    let task = setInterval(
      () => {
        if (!_warnList[0]) {
          clearInterval(task);
        } else {
          const warn = _warnList[0];
          // 执行业务
          for (let i = 0; i < list.length; i++) {
            const el = list[i];
            const config: SmsConfig = {
              accessKeyId: 'LTAI5tEidvcjyvfvLvSUBT3i',
              accessKeySecret: 'CDg4BZiqnQPEqbUCZHlwzoOexjSeiX',
            };
            const smsSender = new SmsSender(config);
            const data = {
              PhoneNumbers: el.phone,
              SignName: '五号风控',
              TemplateCode: 'SMS_123666936',
              TemplateParam: JSON.stringify({
                username: el.name,
                imei: IMEI,
                warn: warn,
              }),
            };
            smsSender.sendSms(data);
          }
          _warnList.splice(0, 1);
        }
      },
      1 * 60 * 1000,
    );
  }

  // 报警接口
  public async warn(identifier: string, _warnList: string[]) {
    const deviceInfo: Device = await this.device.findOneBy({ identifier });

    // 未超过间隔时间不执行
    // const logLast: Log[] = await this.log.find({
    //   where: { p_created_at: deviceInfo.id },
    //   order: { p_created_at: 'DESC' },
    //   take: 1,
    // });
    const tenMinutesAgo = new Date();
    tenMinutesAgo.setMinutes(tenMinutesAgo.getMinutes() - deviceInfo.interval);
    const logLast: Log[] = await this.log
      .createQueryBuilder()
      .where('deviceId = :deviceId', { deviceId: deviceInfo.id })
      .andWhere('p_created_at >= :time', { time: tenMinutesAgo })
      .getMany();
    // if (logLast && logLast.length > 0) {
    //   const t = getMinutesDiff(logLast[0].p_created_at);
    //   if (deviceInfo.interval > t) {
    //     return;
    //   }
    // }
    let warnList = _warnList.filter((el) => !logLast.find((v) => v.warn == el));
    let isSms = true;
    let isCall = true;
    let executeWarnList: string[] = [];
    const sysInfo: Sys = await this.sys.findOneBy({ id: 1 });
    // 查询所有的报警人
    const callerList: Caller[] = await this.caller.findBy({
      deviceId: deviceInfo.id,
    });
    const phoneCallerList = callerList.filter((v) => v.isCall);
    const smsCallerList = callerList.filter((v) => v.isSms);
    for (let i = 0; i < warnList.length; i++) {
      const warn = warnList[i];
      // 记录报警记录
      await this.log.save({
        warn,
        deviceId: deviceInfo.id,
        p_created_at: new Date(),
      });
      const userInfo: User = await this.user.findOneBy({
        id: deviceInfo.userId,
      });
      // 查看金额是否足够
      if (userInfo.smsMoney >= sysInfo.smsMoney * smsCallerList.length) {
        await this.user.update(
          { id: userInfo.id },
          {
            smsMoney:
              userInfo.smsMoney - sysInfo.smsMoney * smsCallerList.length,
          },
        );
      } else {
        isSms = false;
      }
      // 查看金额是否足够
      if (userInfo.phoneMoney >= sysInfo.phoneMoney * phoneCallerList.length) {
        await this.user.update(
          { id: userInfo.id },
          {
            phoneMoney:
              userInfo.phoneMoney - sysInfo.phoneMoney * phoneCallerList.length,
          },
        );
      } else {
        isCall = false;
      }
      executeWarnList.push(warn);
    }
    if (isSms) {
      this.smsTasks(smsCallerList, executeWarnList, deviceInfo.IMEI);
    }
    if (isCall) {
      // this.phoneTasks(phoneCallerList, executeWarnList);
    }

    return;
  }

  /**
   *
   * @description 查询报警列表
   */
  public async getPowerList(param: PgaeDto) {
    const list: any = await this.log
      .createQueryBuilder()
      .where('deviceId = :deviceId', { deviceId: param.deviceId })
      .orderBy('p_created_at', 'DESC')
      .skip((param.page - 1) * param.pageSize)
      .take(param.pageSize)
      .getManyAndCount();
    let responseParam: ResponseParam = {
      message: ApiErrorCode.LACK_GET_SUCCESS,
      data: list[0],
      count: list[1],
    };
    return Response(responseParam);
  }

  // 用户扫码添加设备
  public async ScanBindDevice(userId: number, params: any) {
    const userInfo: User = await this.user.findOneBy({ id: userId });
    if (userInfo.role != AdminRole.General) {
      return CurrentError.ID_ERROR;
    }
    const deviceInfo: Device = await this.device.findOneBy({
      identifier: params.identifier,
    });
    if (!deviceInfo) {
      return CurrentError.ID_NOT;
    }
    const deviceUserInfo: User = await this.user.findOneBy({
      id: deviceInfo.userId,
    });
    if (deviceUserInfo.role === AdminRole.General) {
      return CurrentError.BIND_OLD;
    }
    try {
      await this.device.update(
        { identifier: params.identifier },
        {
          userId: userInfo.id,
          userName: userInfo.name,
          type: params.type,
          IMEI: params.IMEI,
          name: params.name,
          position: params.position,
          address: params.address,
          installPosition: params.installPosition,
        },
      );
      let responseParam: ResponseParam = {
        message: ApiErrorCode.LACK_UPDATE_SUCCESS,
        data: null,
      };
      return Response(responseParam);
    } catch (error) {
      console.log(error);
      return CurrentError.BIND_FIAL;
    }
  }

  public async updateGroup(params: any[]) {
    try {
      for (let i = 0; i < params.length; i++) {
        await this.device.update(
          { identifier: params[i].identifier },
          { userId: params[i].userId, userName: params[i].userName },
        );
      }
      let responseParam: ResponseParam = {
        message: ApiErrorCode.LACK_UPDATE_SUCCESS,
        data: null,
      };
      return Response(responseParam);
    } catch (error) {
      CurrentError.LACK_UPDATE_FAIL;
    }
  }
}
